# coding: utf-8
"""Qingstor
Usage:
  algo_index img_seg --modelVersion=<modelVersion> --token=<token> --buildid=<buildid> [--datasets=<datasets>]
  algo_index -h | --help
  algo_index --version

Options:
  -h --help     帮助.
  -v --version     查看版本号.
  --modelVersion=<modelVersion>  模型版本
  --params=<params>  参数.
  --token=<token>  微信token
  --product=<product>  product设置 [default: stdci].
  --name=<name>  name设置 [default: qe].
  --dirname=<dirname>  dirname设置 [default: default].
"""
import requests
import json
import base64
import os
from datetime import datetime
import time
from docopt import docopt
import pandas as pd
import dataframe_image as dfi
from ci_conclude.weixin import send_message1,send_message
from PIL import Image
from ci_conclude.qingstor import upload_personal
from ci_conclude.jenkins_manage import JenkinsManage
from ci_conclude.mongo_manage import Mongo
import matplotlib.pyplot as plt
import traceback
# from ci_conclude.jenkins_manage import JenkinsManage

BASE_DIR = "/tmp/"

mongo = Mongo()


def get_mongo_data(model_version):
    i = 0
    mongo = Mongo()
    now = datetime.utcnow()
    print(f"---{now}---")
    while True:
        time.sleep(60)
        status = mongo.find_one({"timestamp": {"$gte": now}, "model_version": model_version})
        i += 1
        print(now)
        print(f" 第{i}次查询")
        if status is not None and i < 100:
            return status


def jenkins_build(job_name, params):
    if isinstance(params, str):
        params = json.loads(params)
    jenkins = JenkinsManage(username="a2UudGlhbg==", password='VGsxMjMuY29t')
    jenkins.job_start(job_name=job_name, job_param_dict=params)
    time.sleep(20)
    jenkins.check_job_status(job_name=job_name, buildid="lastBuild")


def sonar_scan(job_name):
    username = base64.b64decode("a2UudGlhbg==").decode()
    passwod = base64.b64decode('VGsxMjMuY29t').decode()
    os.system(
        f'curl https://{username}:{passwod}@ci.ecarx.com.cn/view/stdci/job/{job_name}/buildWithParameters?SCM_REVISION=origin/master&APP_ENV=ci&token={job_name}')


def read_image(img_path):
    image = Image.open(img_path)
    image.convert("RGB")
    return image


def mreg_image(image1, image2, image_file):
    ys = BASE_DIR + "image/ys.jpg"
    cj = BASE_DIR + "image/cj.jpg"
    ys_image = read_image(ys)
    cj_image = read_image(cj)
    image1 = read_image(image1)
    image2 = read_image(image2)

    w = max(image1.width, image2.width)
    h = ys_image.height + cj_image.height + image1.height + image2.height

    n_image = Image.new('RGB', (w, h), (255, 255, 255))

    n_image.paste(cj_image, (int(w / 2 - cj_image.width / 2), 0))
    n_image.paste(image1, (int(w / 2 - image1.width / 2), cj_image.height))
    n_image.paste(ys_image, (int(w / 2 - ys_image.width / 2), ys_image.height + image1.height))
    n_image.paste(image2, (int(w / 2 - image2.width / 2), ys_image.height + cj_image.height + image1.height))
    n_image.save(image_file)


class AlgoIndex():
    def __init__(self, model_version, metrics_list, metrics_type):
        self.model_version = model_version.split("/")[-1]
        self.metrics_list = metrics_list
        self.metrics_type = metrics_type
        self.template = mongo.find_one({"name": f"{self.metrics_type}_template"}, collection="Template").get("data")
        self.threshold = mongo.find_one({"name": f"{self.metrics_type}_threshold"}, collection="Template").get("data")
        self.index_corr = mongo.find_one({"name": "index_corr"}, collection="Template").get("data")

    def _json_to_dataframe(self, metrics):
        """
        指标json格式转换为dataframe
        @param metrics: json数据
        @return: df数据
        """
        df = pd.DataFrame()
        for i in self.metrics_list:
            series = pd.Series(metrics.get(i), name=i)
            df = df.append(series)
        df = df.T
        return df

    def _get_threshold_dataframe(self, metrics):
        df = pd.DataFrame()
        for i in self.template.keys():
            series = pd.Series(metrics.get(i), name=i)
            df = df.append(series)

        return df

    def change_color(self, val):
        color = 'red' if '-' in val else 'green'
        return 'color:%s' % color

    def _drop_index(self, df):
        """
        删除没用的数据
        @param df: dataframe 需要操作的dataframe
        @param metrics_type: str 传入的场景类别
        @return: dataframe 返回删除后的数据
        """
        # 做两个集合的对称差集
        drop_list = set(set(df.index)).difference(self.template.keys())
        return df.drop(drop_list)

    def _comparison_threshold(self, metrics):
        """
        与阈值进行对比
        @param metrics: df 结果数据
        @return: df 结果数据与阈值数据对比后的结果
        """
        threshold_df = self._get_threshold_dataframe(self.threshold)
        diff = metrics.round(4).sub(threshold_df.round(4))
        diff[diff < 0] = 1
        return diff

    def _save_image(self, metrics, histroy):
        metrics = self._drop_index(metrics)
        histroy = self._drop_index(histroy)
        diff = metrics.sub(histroy)
        # 统计数量
        index_reduction = diff.copy().round(4)
        index_rise = diff.copy().round(4)

        index_reduction[index_reduction >= 0] = 0
        index_reduction[index_reduction < 0] = 1

        index_rise[index_rise <= 0] = 0
        index_rise[index_rise > 0] = 1
        index_reduction_count = index_reduction.sum().sum()
        index_rise_count = index_rise.sum().sum()

        diff["temporary_s"] = "("
        diff["temporary_e"] = ")"
        diff['temporary'] = '-'
        df = metrics.round(4).astype("str")
        diff = diff.round(4).astype("str").replace('-0.0', '0.0').fillna('-')
        # 遍历所有的指标
        for i in self.metrics_list:
            if i in df.columns:
                df[i] = df[i].str.cat([diff["temporary_s"], diff[i], diff["temporary_e"]])

        # df = self._drop_index(df, self.metrics_type)
        # 转换中文
        df.rename(index=self.template, inplace=True)
        df = df.style.applymap(self.change_color)

        dfi.export(df, os.path.join(BASE_DIR, f'{self.metrics_type}_image.jpg'))
        # df = df.to_json(orient='columns')
        return index_reduction_count, index_rise_count

    def _index_mapping(self, data):
        """
        指标映射，将数据库中的指标与接口中的指标进行对应转换
        @param data: dict 数据库中的返回数据
        @return: dict 想要的指标数据
        """
        text = dict()
        for k, v in self.index_corr.items():
            text[v] = data.get(k)
        return text

    def _histroy_metrics(self):
        filter = {"model_version": {"$ne": self.model_version}}
        data = mongo.find_one(filter=filter, sort_key=[('timestamp', -1)])
        if data is None:
            return None
        else:
            histroy_metrice = data.get('model_metrics')
            histroy_metrice = self._index_mapping(histroy_metrice)
            histroy_metrice = self._json_to_dataframe(histroy_metrice)
        return histroy_metrice



    def processing_data(self, metrics_type, metrics):
        """
        开始处理数据，然后将数据存储为照片
        将{指标：{元素}}改为{元素:{指标}}
        @param metrics_type: 指标类型
        @param metrics: 指标字典
        @return:
        """
        metrics_df = self._json_to_dataframe(metrics)
        # 计算低于阈值的数据
        comparison_threshol = self._comparison_threshold(metrics_df)
        # 计算出低于阈值的结果
        below_standard = comparison_threshol.sum().sum()
        # 读取历史记录
        histroy = self._histroy_metrics()
        # 保存为图片
        index_reduction, index_rise = self._save_image(metrics_df, histroy)
        return below_standard, index_reduction, index_rise

    def get_cybermonitor_index(self, metrics_type):
        """
        用于获取cybermonitor的指标
        @param model_version: str 模型版本
        @param metrics_list: list 所需指标
        @param metrics_type: 指标列别["by_category",by_scenario]
        @return:
        """


        data = get_mongo_data(self.model_version).get("model_metrics")
        metrics = self._index_mapping(data)

        below_standard_count, index_reduction_count, index_rise_count = self.processing_data(
            metrics_type, metrics)

        return metrics, below_standard_count, index_reduction_count, index_rise_count


def main(job_name='flint_seg-eval', params={}, model_version="best_epoch8_min_train_loss_8.7370.pth", metrics_list=None,
         token="7e93d83d-c878-4736-bdbc-e33bb2ff679d", buildid=1, model_name='图像分割'):
    # 启动jenkins
    jenkins_build(job_name=job_name, params=params)
    # classification = ["scenario", "category"]
    classification = ["category"]
    index_reduction_count = index_rise_count = below_standard_count = 0

    for i in classification:
        ai = AlgoIndex(model_version, metrics_list, i)
        text, below_standard, index_reduction, index_rise = ai.get_cybermonitor_index(i)
        index_reduction_count += int(index_reduction)
        index_rise_count += int(index_rise)
        below_standard_count += int(below_standard)
    now = datetime.utcnow()
    image_file = "result" + str(now.timestamp()) + ".jpg"
    image_path = os.path.join(BASE_DIR, f'image/{image_file}')
    # 合并图片
    mreg_image(os.path.join(BASE_DIR, 'scenario_image.jpg'), os.path.join(BASE_DIR, 'category_image.jpg'),
               image_path)
    # 上传图片
    upload_personal(path=image_path, name='ci', dirname='algo')
    # 判断测试是否通过
    if index_reduction_count + below_standard_count > 0:
        results = f"""测试不通过"""
    else:
        results = f"""测试通过"""

    content = {
        "card_type": "news_notice",
        "source": {
            "icon_url": "http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/icon.png",
            "desc": "算法项目CI通知"
        },
        "main_title": {
            "title": f"{model_name}",
            "desc": f"第{buildid}次构建"
        },
        "card_image": {
            "url": f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/{image_file}",
            "aspect_ratio": 1.3
        },
        "vertical_content_list": [
            {
                "title": "测试结论:",
                "desc": results
            }
        ],
        "horizontal_content_list": [
            {
                "keyname": "指标上升",
                "value": f"{index_rise_count} 个",
                "type": 1,
                "url": f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/{image_file}",

            },
            {
                "keyname": "指标降低",
                "value": f"{index_reduction_count} 个",
                "type": 1,
                "url": "http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/aa.jpg"

            },
            {
                "keyname": "低于阈值",
                "value": f"{below_standard_count} 个",
                "type": 1,
                "url": f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/{image_file}",

            }
        ],
        "jump_list": [
            {
                "type": 1,
                "url": f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/{image_file}",
                "title": "算法构建稳定性进行中"
            },
            {
                "type": 1,
                "url": f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/{image_file}",
                "title": "算法混沌测试进行中"
            }

        ],
        "card_action": {
            "type": 1,
            "url": f"http://ecarx.stor.ecarx.com.cn/autobuildtestline/ci/algo/{image_file}",
            "appid": "APPID",
            "pagepath": "PAGEPATH"
        }}
    # 发送企业微信
    send_message1(content=content, token=token, msgtype='template_card')

if __name__ == '__main__':
    arguments = docopt(__doc__, version="1.0.0")
    cases = [k for k, v in arguments.items() if not k.startswith("--") and v == True]
    modelVersion = arguments["--modelVersion"]
    token = arguments["--token"]
    buildid = arguments["--buildid"]

    if len(cases[0]) > 0 and cases[0] == "img_seg":
        datasets = arguments["--datasets"]
        metricsList = ["MIOU", "ACC", "F1score", "precision", "recall"]
        params = {
            "SCM_REVISION": "origin/feat/seg_eval_ci",
            "ACTION": "deploy",
            "APP_ENV": "dev",
            "APP_ENV_ID": 1,
            "RUN_AS_ROOT": True,
            "RUN_CMD": "python3 flint/evaluation/semseg/eval_by_scn_task_multiprocess_cluster.py  --num_proc=4",
            "GPU_NUM": 2,
            "MODEL_VERSION": modelVersion,
            "COLLECTION": "segmentation",
            "UPLOAD_TO_DB": True,
            "DATASETS": "\\\"ECARX Perception Segmentation - Evaluation Set\\\"",
            "DESCRPTION": "You should always try to type something here, in order to notify people what you are doing"
        }
        model_name = '图像分割'
    try:
        main(model_version=modelVersion, model_name=model_name, metrics_list=metricsList, params=params, token=token,
         buildid=buildid)
    except Exception:
        content = f"{modelVersion}模型执行失败,Build ID: {buildid}"
        send_message(content, token="7e93d83d-c878-4736-bdbc-e33bb2ff679d", msgtype="text")
        print(traceback.print_exc())
